package mensch;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;

public class Game implements Serializable{
	private final static Logger LOG = Logger.getLogger(Game.class.getName());
	private List<Player> players;
	private Table table;
	private Player leader;
	private int roundCounter = 1;
	private String opponentDiceValues = "";
	private int playerDiceValue = 1;
	private boolean inProgress = true;
	private boolean skipOpponent = false;
	private long startTime = System.currentTimeMillis();
        private String elapsedTime = "0 min 0 sec";

	/**
	 * number of players. For UE2: 2
	 */
	private int numberOfPlayers = 2;
	
        public Game(Player p){
           	LOG.debug("Konstruktor mit folgendem Player: " + p.getUsername());
                players = new ArrayList<Player>();
                
		players.add(new Player(p.getUsername(), 0));
		players.add(new Player("Computer", 1));
		players.add(new Player("Luigi", 2));
		players.add(new Player("Yoshi", 3));
		LOG.debug("Size von der ArrayList: " +players.size());
		table = new Table(players);
		
		// by default players 1 is set as leader to keep it simple
		leader = players.get(0); 
        }
	public Game() {
            LOG.debug("Leerer Game Konstruktor");
	}
	
	public List<Player> getPlayers() {
                LOG.debug("Werde gerade aufgerufen");
		return players;
	}
	
	public Table getTable() {
		return table;
	}
	
	public int getNumberOfPlayers() {
		return numberOfPlayers;
	}
	
	public String getActivePlayerName() {
		return players.get(0).getUsername();
	}
	
	public String getLeaderName() {
		return leader.getUsername();
	}
	
	public int getCurrentRound() {
		return roundCounter;
	}
	
	public String getOpponentDiceValues() {
		return opponentDiceValues;
	}
	
	public boolean isInProgress() {
		return inProgress;
	}
	
	public int getPlayerDiceValue() {
		return playerDiceValue;
	}
	
	public String getTime() {
            if (!inProgress) return elapsedTime;
            
            long time = System.currentTimeMillis() - startTime;
            elapsedTime = String.format("%d min, %d sec", TimeUnit.MILLISECONDS
                    .toMinutes(time), TimeUnit.MILLISECONDS.toSeconds(time),
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS
                                    .toMinutes(time)));
            return elapsedTime;
	}
	
	public void startTurn() {
                if (!inProgress) return;
                
		LOG.debug("New turn");
                for (int activePlayerId = 0; activePlayerId < numberOfPlayers; activePlayerId++) {
			if (activePlayerId == 1 && skipOpponent) {
				skipOpponent = false;
				continue;
			}
			roll(activePlayerId);
		}
		if (inProgress) roundCounter++;
	}
	
	private void roll(int activePlayerId) {
		int diceValue = rollDice();
		// int diceValue = 1; // Debug

		Player player = this.players.get(activePlayerId);
		Pawn pawn = player.getPawns().get(0);
		Field currentField = pawn.getField();
		int newFieldIndex;

		if (activePlayerId == 1) {
			if (opponentDiceValues.equals("")) {
				opponentDiceValues = Integer.toString(diceValue);
			} else {
				opponentDiceValues += " - " + diceValue;
			}
		} else {
			opponentDiceValues = "";
			playerDiceValue = diceValue;
		}

		// Im Starthaus
		if (currentField instanceof HomeField) {
			if (diceValue == 6) {
				newFieldIndex = player.getFirstFieldIndex();
				makeMove(pawn, newFieldIndex);
				pawn.incrementFieldCounter(1);
			}

			// nicht im Starthaus
		} else {
			int currentFieldIndex = currentField.getFieldIndex();
			newFieldIndex = currentFieldIndex + diceValue;

			if (newFieldIndex > 39) {
				newFieldIndex -= 40;
			}
			pawn.incrementFieldCounter(diceValue);

			int fieldCounter = pawn.getFieldCounter();
			if (fieldCounter <= 40) {
				makeMove(pawn, newFieldIndex);
			} else {
				int goalFieldCounter = fieldCounter - 40;
				if (goalFieldCounter <= 4) {
					int goalFieldIndex = player.getFirstGoalIndex()
							+ goalFieldCounter - 1;
					makeMove(pawn, goalFieldIndex);
					inProgress = false;
					// Spiel vorbei
				} else {
					// Ueberwuerfelt -> Kein Zug moeglich
				}
			}
		}

		// find out leader
		if (player.getProgress() > leader.getProgress()) {
			leader = player;
		}

		if (diceValue == 6) {
			if (activePlayerId == 1) {
				roll(activePlayerId);
			} else {
				skipOpponent = true;
			}
		}
	}
	
	private void makeMove(Pawn pawn, int newFieldIndex) {
		Field newField = table.getFields().get(newFieldIndex);
		
		// check if field is occupied
		if (newField.getPawnOnField() != null) {
			Pawn pawnOnField = newField.getPawnOnField();
			Player pawnOnFieldOwner = pawnOnField.getPlayer();
			Field homeField = table.getFields().get(pawnOnFieldOwner.getFirstHomeIndex());
			pawnOnField.moveTo(homeField);
			pawnOnField.resetCounter();
		}
		
		pawn.moveTo(newField);
	}
	
	private int rollDice() {
		return new Random().nextInt(6) + 1;
	}
	
	public String getPlayerName(int playerID) {
		return getPlayers().get(playerID).getUsername();
	}
	
	public String getPlayerName() {
		return getActivePlayerName();
	}
	
	public int getCurrentDiceValue() {
		return getPlayerDiceValue();
	}
	
	public String getFieldTitle(int fieldIndex) {
		Field field = getTable().getFields().get(fieldIndex);
		String fieldTitle = field.getTitle();
		
		if (field.getPawnOnField() != null) {
			fieldTitle += ": " + field.getPawnOnField().getPlayer().getUsername();
		}
		
		return fieldTitle;
	}
	
	public String getFieldImageFilename(int fieldIndex) {
		Field field = getTable().getFields().get(fieldIndex);
		String fieldImageFilename = field.getImageFilename();
		
		if (field.getPawnOnField() != null) {
			fieldImageFilename += "_player" + (field.getPawnOnField().getPlayer().getPlayerID()+1);
		}
		
		return fieldImageFilename + ".png";
	}
	
	public String getRecentDiceValues() {
		return getOpponentDiceValues();
	}
}
